home *** CD-ROM | disk | FTP | other *** search
/ Cream of the Crop 1 / Cream of the Crop 1.iso / PROGRAM / UCRASM25.ARJ / PRINTF.ASM < prev    next >
Assembly Source File  |  1991-10-12  |  15KB  |  712 lines

  1. StdGrp        group    stdlib,stddata
  2. stddata        segment    para public 'sldata'
  3. stddata        ends
  4. ;
  5. stdlib        segment    para public 'slcode'
  6.         assume    cs:stdgrp
  7. ;
  8.         extrn    sl_Putc:far, sl_Puti:far, sl_ISize:far
  9.         extrn    sl_Putw:far, sl_Puth:far
  10.         extrn    sl_Putu:far, sl_PutUL:far, sl_ULSize:far
  11.         extrn    sl_LSize:far, sl_USize:far, sl_PutL:far
  12. ;
  13. putc        equ    sl_putc
  14. puti        equ    sl_puti
  15. ISize        equ    sl_ISize
  16. putw        equ    sl_putw
  17. puth        equ    sl_puth
  18. putu        equ    sl_putu
  19. putul        equ    sl_putul
  20. ulsize        equ    sl_ulsize
  21. lsize        equ    sl_lsize
  22. usize        equ    sl_usize
  23. putl        equ    sl_putl
  24. ;
  25. ;
  26. ; Printf- Like the "C" routine by the same name.  Calling sequence:
  27. ;
  28. ;               call    printf
  29. ;               db      "format string",0
  30. ;               dd      item1, item2, ..., itemn
  31. ;
  32. ; The format string is identical to "C".  Item1..Itemn are pointers to
  33. ; values to print for this string.  Each item must be matched by the
  34. ; corresponding "%xxx" item in the format string.
  35. ;
  36. ; Format string format:
  37. ;
  38. ; 1)    All characters, except the following, are printed to the standard
  39. ;       output as-is.
  40. ;
  41. ; 2)    "\" is the escape character.  Anything following it is printed
  42. ;       as-is except standard "C" values like \r, \n, \b, \t, etc.  If
  43. ;       a decimal digit follows the back-slash, printf assumes that this
  44. ;       is a hexadecimal number and converts following three digits to
  45. ;       an ASCII character and prints it.  Other back-slash operators are
  46. ;       just like those for "C".
  47. ;
  48. ; 3)    Format Control Strings:
  49. ;
  50. ;    General format:  "%s\cn^f" where:
  51. ;                s = -
  52. ;                n = a decimal integer
  53. ;                c = a fill character
  54. ;                ^ = ^
  55. ;                f = a format character
  56. ;
  57. ;            All fields except "%" and "f" are optional.
  58. ;
  59. ;    s = -       Left justify value and use fill character.
  60. ;    \c present    Use "c" as fill character.
  61. ;    n present    Use "n" as the minimum field width.
  62. ;    ^ present    The address associated with f is the address of a
  63. ;                pointer to the object, not the address of
  64. ;                the object itself.  The pointer is a far ptr.
  65. ;
  66. ;    f is one of the following
  67. ;
  68. ;        d -    Print signed integer in decimal notation.
  69. ;        i -    Print signed integer in decimal notation.
  70. ;        x -    Print word value in hexadecimal notation.
  71. ;        h -    Print byte value in hexadecimal notation.
  72. ;        u -    Print unsigned integer in decimal notation.
  73. ;        c -    Print character.
  74. ;        s -    Print string.
  75. ;
  76. ;        ld-    Print long signed integer.
  77. ;        li-    Print long unsigned integer.
  78. ;        lx-    Print long hexadecimal number.
  79. ;        lu-    Print long unsigned number.
  80. ;
  81. ;
  82. ;    Calling Sequence:
  83. ;
  84. ;        call    Printf
  85. ;        db    "Format String",0
  86. ;        dd    adrs1, adrs2, ..., adrsn
  87. ;
  88. ;    Where the format string is ala "C" (and the descriptions above)
  89. ;    and adrs1..adrsn are addresses (far ptr) to the items to print.
  90. ;    Unless the "^" modifier is present, these addresses are the actual
  91. ;    addresses of the objects to print.
  92. ;
  93. ;
  94. ;
  95. cr        equ    0dh
  96. ff        equ    0ch
  97. lf        equ    0ah
  98. tab        equ    09h
  99. bs        equ    08h
  100. ;
  101. RtnAdrs        equ    2[bp]
  102. ;
  103.         public  sl_printf
  104. sl_printf    proc    far
  105.         push    bp
  106.         mov    bp, sp
  107.         pushf
  108.         push    ax
  109.         push    bx
  110.         push    cx
  111.         push    dx
  112.         push    di
  113.         push    si
  114.         push    es
  115.         push    ds
  116. ;
  117. ; Get pointers to the return address (format string).
  118.         cld
  119.         les    di, RtnAdrs
  120.         lds    si, RtnAdrs
  121. ;
  122. ; Okay, search for the end of the format string.  After these instructions,
  123. ; di points just beyond the zero byte at the end of the format string.  This,
  124. ; of course, points at the first address beyond the format string.
  125. ;
  126.         mov    al, 0
  127.         mov    cx, 65535
  128.     repne    scasb
  129. ;
  130. PrintItems:    lodsb            ;Get char si points at.
  131.         cmp    al, 0        ;EOS?
  132.         jz    PrintfDone
  133.         cmp    al, "%"        ;Start of a format string?
  134.         jz    FmtItem
  135.         cmp    al, "\"        ;Escape character?
  136.         jnz    PrintIt
  137.         call    GetEscChar
  138. PrintIt:    call    Putc
  139.         jmp    PrintItems
  140. ;
  141. FmtItem:    call    GetFmtItem    ;Process the format item here.
  142.         jmp    PrintItems
  143. ;
  144. PrintfDone:    mov    RtnAdrs, di    ;Put out new return address.
  145.         pop    ds
  146.         pop    es
  147.         pop    si
  148.         pop    di
  149.         pop    dx
  150.         pop    cx
  151.         pop    bx
  152.         pop    ax
  153.         pop    bp
  154.         popf
  155.         ret
  156. sl_printf       endp
  157. ;
  158. ; GetEscChar- Handles items immediately following the escape character "\".
  159. ;
  160. ;    Special escape characters (upper/lower case is acceptable):
  161. ;
  162. ;        n    Newline (cr/lf)
  163. ;        t    tab
  164. ;        b    backspace
  165. ;        r    return
  166. ;        l    line feed
  167. ;        f    formfeed
  168. ;        \    \
  169. ;        %    &
  170. ;        0xhh    Char with hex character code hh.  Must have exactly
  171. ;            two hexadecimal digits.
  172. ;
  173. GetEscChar    proc    near
  174.         lodsb            ;Get next character
  175.         cmp    al, 'n'
  176.         je    RtnNL
  177.         cmp    al, 'N'
  178.         je    RtnNL
  179.         cmp    al, 't'
  180.         je    RtnTab
  181.         cmp    al, 'T'
  182.         je    RtnTab
  183.         cmp    al, 'b'
  184.         je    RtnBS
  185.         cmp    al, 'B'
  186.         je    RtnBS
  187.         cmp    al, 'r'
  188.         je    RtnRtn
  189.         cmp    al, 'R'
  190.         je    RtnRtn
  191.         cmp    al, 'l'
  192.         je    RtnLF
  193.         cmp    al, 'L'
  194.         je    RtnLF
  195.         cmp    al, 'f'
  196.         je    RtnFF
  197.         cmp    al, 'F'
  198.         je    RtnFF
  199. ;
  200. ; Check for the presence of a 0xhh value here:
  201. ;
  202.         cmp    al, '0'
  203.         jne    RtnChar
  204.         cmp    byte ptr [si], 'x'
  205.         je    GetHex
  206.         cmp    byte ptr [si], 'X'
  207.         jne    RtnChar
  208. ;
  209. ; Okay, process the hex value here.  Note that exactly two hex digits must
  210. ; follow the 0x.
  211. ;
  212. GetHex:        inc    si        ;Point at first hex digit.
  213.         lodsb            ;Get first hex digit.
  214.         and    al, 05fh    ;l.c. -> u.c.
  215.         cmp    al, 'A'
  216.         jb    GotIt
  217.         sub    al, '7'
  218. GotIt:        shl    al, 1        ;Put into H.O. nibble.
  219.         shl    al, 1
  220.         shl    al, 1
  221.         shl    al, 1
  222.         mov    ah, al        ;Save for later
  223.         lodsb            ;Get next char.
  224.         and    al, 05fh
  225.         cmp    al, 'A'
  226.         jb    GotIt2
  227.         sub    al, '7'
  228. GotIt2:        and    al, 0fh
  229.         or    al, ah
  230.         ret            ;Return hex constant.
  231. ;
  232. ; RtnNL (return Newline) cheats.  It needs to return two characters.
  233. ; Since GetEscChar only returns a single character, this code goes ahead
  234. ; and calls putc to output the CR and the returns the LF.
  235. ;
  236. RtnNL:        mov    al, cr
  237.         call    Putc
  238.         mov    al, lf
  239.         ret
  240. ;
  241. RtnTab:        mov    al, tab
  242.         ret
  243. ;
  244. RtnBS:        mov    al, bs
  245.         ret
  246. ;
  247. RtnRtn:        mov    al, cr
  248.         ret
  249. ;
  250. RtnLF:        mov    al, lf
  251.         ret
  252. ;
  253. RtnFF:        mov    al, ff
  254. RtnChar:    ret
  255. ;
  256. GetEscChar    endp
  257. ;
  258. ;
  259. ;
  260. GetFmtItem    proc    near
  261.         lodsb                ;Get char beyond "%"
  262. ;
  263.         mov    cx, 1            ;Default field width is 1.
  264.         mov    dl, 0            ;Default is right justified
  265.         mov    dh, ' '            ;Default fill char is space.
  266.         mov    ah, ' '            ;Assume straight ptr, not handle.
  267. ;
  268. ; See if the user wants the value left justified:
  269. ;
  270.         cmp    al, '-'
  271.         jne    NotLeftJust
  272.         inc    dl            ;Set to right justified
  273.         lodsb                ;Get next character.
  274. ;
  275. ; See if the user wants to change the padding character.
  276. ;
  277. NotLeftJust:    cmp    al, '\'
  278.         jne    NoPadChange
  279.         lodsb                ;Get Padding Character.
  280.         mov    dh, al            ;Save padding character.
  281.         lodsb                ;Get next character
  282. ;
  283. ; See if the user wants a different field width:
  284. ;
  285. NoPadChange:    cmp    al, '0'
  286.         jb    NoFldWidth
  287.         cmp    al, '9'
  288.         ja    NoFldWidth
  289.         call    GetDecVal
  290. ;
  291. ; See if the user wants to specify a handle rather than a straight pointer
  292. ;
  293. NoFldWidth:    cmp    al, '^'
  294.         jne     ChkFmtChars
  295.         mov    ah, al
  296.         lodsb                ;Skip "^" character
  297. ;
  298. ; Okay, process the format characters down here.
  299. ;
  300. ChkFmtChars:    and    al, 05fh        ;l.c. -> U.C.
  301.         cmp    al, 'D'
  302.         je    PrintDec
  303.         cmp    al, 'I'
  304.         je    PrintDec
  305.         cmp    al, 'C'
  306.         je    PrintChar
  307. ;
  308.         cmp    al, 'X'
  309.         jne    TryH
  310.         jmp    PrintHexWord
  311. ;
  312. TryH:        cmp    al, 'H'
  313.         jne    TryU
  314.         jmp    PrintHexByte
  315. ;
  316. TryU:        cmp    al, 'U'
  317.         jne    TryString
  318.         jmp    PrintUDec
  319. ;
  320. TryString:    cmp    al, 'S'
  321.         jne    TryLong
  322.         jmp    PrintString
  323. ;
  324. TryLong:        cmp    al, 'L'
  325.         jne    Default
  326. ;
  327. ; If we've got the "L" modifier, this is a long value to print, get the
  328. ; data type character as the next value:
  329. ;
  330.         lodsb
  331.         and    al, 05fh        ;l.c. -> U.C.
  332.         cmp    al, 'D'
  333.         je    JmpDec
  334.         cmp    al, 'I'
  335.         jne    TryLU
  336. JmpDec:        jmp    LongDec
  337. ;
  338. TryLU:        cmp    al, 'U'
  339.         jne    TryX
  340.         jmp    LongU
  341. ;
  342. TryX:        cmp    al, 'X'
  343.         jne    Default
  344.         jmp    LongX
  345. ;
  346. ;
  347. ;
  348. ; If none of the above, simply return without printing anything.
  349. ;
  350. Default:        ret
  351. ;
  352. ;
  353. ;
  354. ;
  355. ;
  356. ; Print a signed decimal value here.
  357. ;
  358. PrintDec:    call    GetPtr            ;Get next pointer into ES:BX
  359.         mov    ax, es:[bx]        ;Get value to print.
  360.         call    ISize            ;Get the size of this guy.
  361.         sub    cx, ax                 ;Compute padding
  362.         mov    ax, es:[bx]        ;Retrieve value to print.
  363.         js    NoPadDec        ;Is CX negative?
  364.         cmp    dl, 0            ;Right justified?
  365.         jne    LeftJustDec
  366.         call    PrintPad        ;Print padding characters
  367.         call    Puti            ;Print the integer
  368.         ret                ;We're done!
  369. ;
  370. ; Print left justified value here.
  371. ;
  372. LeftJustDec:    call    Puti
  373.         call    PrintPad
  374.         ret
  375. ;
  376. ; Print non-justified value here:
  377. ;
  378. NoPadDec:    call    Puti
  379.         ret
  380. ;
  381. ;
  382. ;
  383. ; Print a character variable here.
  384. ;
  385. PrintChar:    call    GetPtr            ;Get next pointer into ES:BX
  386.         mov    al, es:[bx]        ;Retrieve value to print.
  387.                 dec    cx
  388.         js    NoPadChar        ;Is CX negative?
  389.         cmp    dl, 0            ;Right justified?
  390.         jne    LeftJustChar
  391.         call    PrintPad        ;Print padding characters
  392.         call    Putc            ;Print the character
  393.         ret                ;We're done!
  394. ;
  395. ; Print left justified value here.
  396. ;
  397. LeftJustChar:    call    Putc
  398.         call    PrintPad
  399.         ret
  400. ;
  401. ; Print non-justified character here:
  402. ;
  403. NoPadChar:    call    Putc
  404.         ret
  405. ;
  406. ;
  407. ;
  408. ;
  409. ; Print a hexadecimal word value here.
  410. ;
  411. PrintHexWord:    call    GetPtr            ;Get next pointer into ES:BX
  412.         mov    ax, es:[bx]        ;Get value to print.
  413.         sub    cx, 4            ;Compute padding
  414.         js    NoPadHexW        ;Is CX negative?
  415.         cmp    dl, 0            ;Right justified?
  416.         jne    LeftJustHexW
  417.         call    PrintPad        ;Print padding characters
  418.         call    Putw            ;Print the hex value
  419.         ret                ;We're done!
  420. ;
  421. ; Print left justified value here.
  422. ;
  423. LeftJustHexW:    call    Putw
  424.         call    PrintPad
  425.         ret
  426. ;
  427. ; Print non-justified value here:
  428. ;
  429. NoPadHexW:    call    Putw
  430.         ret
  431. ;
  432. ;
  433. ;
  434. ;
  435. ; Print hex bytes here.
  436. ;
  437. ;
  438. PrintHexByte:    call    GetPtr            ;Get next pointer into ES:BX
  439.         mov    ax, es:[bx]        ;Get value to print.
  440.         sub    cx, 2            ;Compute padding
  441.         js    NoPadHexB        ;Is CX negative?
  442.         cmp    dl, 0            ;Right justified?
  443.         jne    LeftJustHexB
  444.         call    PrintPad        ;Print padding characters
  445.         call    Puth            ;Print the hex value
  446.         ret                ;We're done!
  447. ;
  448. ; Print left justified value here.
  449. ;
  450. LeftJustHexB:    call    Puth
  451.         call    PrintPad
  452.         ret
  453. ;
  454. ; Print non-justified value here:
  455. ;
  456. NoPadHexB:    call    Puth
  457.         ret
  458. ;
  459. ;
  460. ;
  461. ; Output unsigned decimal numbers here:
  462. ;
  463. PrintUDec:    call    GetPtr            ;Get next pointer into ES:BX
  464.         mov    ax, es:[bx]        ;Get value to print.
  465.         call    USize            ;Get the size of this guy.
  466.         sub    cx, ax                 ;Compute padding
  467.         mov    ax, es:[bx]        ;Retrieve value to print.
  468.         js    NoPadUDec        ;Is CX negative?
  469.         cmp    dl, 0            ;Right justified?
  470.         jne    LeftJustUDec
  471.         call    PrintPad        ;Print padding characters
  472.         call    Putu            ;Print the integer
  473.         ret                ;We're done!
  474. ;
  475. ; Print left justified value here.
  476. ;
  477. LeftJustUDec:    call    Putu
  478.         call    PrintPad
  479.         ret
  480. ;
  481. ; Print non-justified value here:
  482. ;
  483. NoPadUDec:    call    Putu
  484.         ret
  485. ;
  486. ;
  487. ;
  488. ;
  489. ; Output a string here:
  490. ;
  491. PrintString:    call    GetPtr            ;Get next pointer into ES:BX
  492. ;
  493. ; Compute the length of the string:
  494. ;
  495.         push    di
  496.         push    cx
  497.         mov    cx, -1
  498.         mov    di, bx
  499.         mov    al, 0
  500.     repne    scasb
  501.         mov    ax, cx
  502.         neg    ax
  503.         dec    ax
  504.         dec    ax
  505.         pop    cx
  506.         pop    di
  507.         sub    cx, ax            ;Field width - String Length.
  508. ;
  509.         js    NoPadStr        ;Is CX negative?
  510.         cmp    dl, 0            ;Right justified?
  511.         jne    LeftJustStr
  512.         call    PrintPad        ;Print padding characters
  513.         call    Puts            ;Print the string
  514.         ret                ;We're done!
  515. ;
  516. ; Print left justified value here.
  517. ;
  518. LeftJustStr:    call    Puts
  519.         call    PrintPad
  520.         ret
  521. ;
  522. ; Print non-justified value here:
  523. ;
  524. NoPadStr:    call    Puts
  525.         ret
  526. GetFmtItem    endp
  527. ;
  528. ;
  529. ;
  530. ; Print a signed long decimal value here.
  531. ;
  532. LongDec:    call    GetPtr            ;Get next pointer into ES:BX
  533.         mov    ax, es:[bx]        ;Get value to print.
  534.         push    dx
  535.         mov    dx, es:2[bx]
  536.         call    LSize            ;Get the size of this guy.
  537.         pop    dx
  538.         sub    cx, ax                 ;Compute padding
  539.         mov    ax, es:[bx]        ;Retrieve value to print.
  540.         js    NoPadLong        ;Is CX negative?
  541.         cmp    dl, 0            ;Right justified?
  542.         jne    LeftJustLong
  543.         call    PrintPad        ;Print padding characters
  544.         mov    dx, es:2[bx]        ;Get H.O. word
  545.         call    PutL            ;Print the integer
  546.         ret                ;We're done!
  547. ;
  548. ; Print left justified value here.
  549. ;
  550. LeftJustLong:    push    dx
  551.         mov    dx, es:2[bx]        ;Get H.O. word
  552.         call    PutL
  553.         pop    dx
  554.         call    PrintPad
  555.         ret
  556. ;
  557. ; Print non-justified value here:
  558. ;
  559. NoPadLong:    mov    dx, es:2[bx]        ;Get H.O. word
  560.         call    Putl
  561.         ret
  562. ;
  563. ;
  564. ; Print an unsigned long decimal value here.
  565. ;
  566. LongU:        call    GetPtr            ;Get next pointer into ES:BX
  567.         mov    ax, es:[bx]        ;Get value to print.
  568.         push    dx
  569.         mov    dx, es:[bx]
  570.         call    ULSize            ;Get the size of this guy.
  571.         pop    dx
  572.         sub    cx, ax                 ;Compute padding
  573.         mov    ax, es:[bx]        ;Retrieve value to print.
  574.         js    NoPadULong        ;Is CX negative?
  575.         cmp    dl, 0            ;Right justified?
  576.         jne    LeftJustULong
  577.         call    PrintPad        ;Print padding characters
  578.         mov    dx, es:2[bx]        ;Get H.O. word
  579.         call    PutUL            ;Print the integer
  580.         ret                ;We're done!
  581. ;
  582. ; Print left justified value here.
  583. ;
  584. LeftJustULong:    push    dx
  585.         mov    dx, es:2[bx]        ;Get H.O. word
  586.         call    PutUL
  587.         pop    dx
  588.         call    PrintPad
  589.         ret
  590. ;
  591. ; Print non-justified value here:
  592. ;
  593. NoPadULong:    mov    dx, es:2[bx]        ;Get H.O. word
  594.         call    Putul
  595.         ret
  596. ;
  597. ;
  598. ; Print a long hexadecimal value here.
  599. ;
  600. LongX:        call    GetPtr            ;Get next pointer into ES:BX
  601.         sub    cx, 8            ;Compute padding
  602.         js    NoPadXLong        ;Is CX negative?
  603.         cmp    dl, 0            ;Right justified?
  604.         jne    LeftJustXLong
  605.         call    PrintPad        ;Print padding characters
  606.         mov    ax, es:2[bx]        ;Get H.O. word
  607.         call    Putw
  608.         mov    ax, es:[bx]
  609.         call    Putw
  610.         ret                ;We're done!
  611. ;
  612. ; Print left justified value here.
  613. ;
  614. LeftJustxLong:    mov    ax, es:2[bx]        ;Get H.O. word
  615.         call    Putw
  616.         mov    ax, es:[bx]        ;Get L.O. word
  617.         call    Putw
  618.         call    PrintPad
  619.         ret
  620. ;
  621. ; Print non-justified value here:
  622. ;
  623. NoPadxLong:    mov    ax, es:2[bx]        ;Get H.O. word
  624.         call    Putw
  625.         mov    ax, es:[bx]
  626.         call    Putw
  627.         ret
  628. ;
  629. ;
  630. ;
  631. ;
  632. ; Puts- Outputs the zero terminated string pointed at by ES:BX.
  633. ;
  634. Puts        proc    near
  635. PutsLp:        mov    al, es:[bx]
  636.         cmp    al, 0
  637.         je    PutsDone
  638.         call    putc
  639.         inc    bx
  640.         jmp    PutsLp
  641. ;
  642. PutsDone:    ret
  643. Puts        endp
  644. ;
  645. ;
  646. ;
  647. ;
  648. ;
  649. ; PrintPad-    Prints padding characters.  Character to print is in DH.
  650. ;        We must print it CX times.  CX must be greater than zero.
  651. ;
  652. PrintPad    proc    near
  653.         push    ax
  654.         mov    al, dh
  655.         jcxz    NoPadding
  656. PPLoop:        call    Putc
  657.         loop    PPLoop
  658. NoPadding:    pop    ax
  659.         ret
  660. PrintPad    endp
  661. ;
  662. ;
  663. ;
  664. ;
  665. ;
  666. ; GetPtr- Grabs the next pointer which DS:DI points at and returns this
  667. ;      far pointer in ES:BX.
  668. ;
  669. GetPtr        proc    near
  670.         les    bx, [di]
  671.         add    di, 4
  672. ;
  673. ; See if this is a handle rather than a pointer.
  674. ;
  675.         cmp    ah, '^'
  676.         jne    NotHandle
  677.         les    bx, es:[bx]
  678. NotHandle:    ret
  679. GetPtr        endp
  680. ;
  681. ;
  682. ;
  683. ;
  684. ;
  685. ; GetDecVal-    Converts the string of decimal digits in AL and [SI] into
  686. ;        an integer and returns this integer in CX.
  687. ;
  688. GetDecVal    proc    near
  689.         push    dx
  690.         dec    si
  691.         xor    cx, cx
  692. DecLoop:    lodsb
  693.         cmp    al, '0'
  694.         jb    NoMore
  695.         cmp    al, '9'
  696.         ja    NoMore
  697.         and    al, 0fh
  698.         shl    cx, 1            ;Compute CX := CX*10 + al
  699.         mov    dx, cx
  700.         shl    cx, 1
  701.         shl    cx, 1
  702.         add    cx, dx
  703.         add    cl, al
  704.         adc    ch, 0
  705.         jmp    DecLoop
  706. NoMore:        pop    dx
  707.         ret
  708. GetDecVal    endp
  709. ;
  710. stdlib        ends
  711.         end
  712.